﻿/*
 * Created by SharpDevelop.
 * User: Edward Wilde (http://blogs.charteris.com/edwardw)
 * Date: 05/07/2007
 * Time: 17:06
 */

using System;
using System.Collections.ObjectModel;
using System.Globalization;
using WatiN.Core;

namespace Wax
{
	/// <summary>
	/// Used to set the value of an <see cref="WatiN.Core.Element">Element</see>
	/// </summary>
	public class SetValueCommand : PropertyCommand
	{

		#region Private fields
		
		/// <summary>
		/// For a <see cref="CommandType.SetValues" /> an array of values to set.
		/// </summary>
		private Collection<string> valuesToSet;
		
		#endregion
		
		#region Public properties
		
		/// <summary>
		/// The value to set the specified <see cref="PropertyType">property</see>.
		/// </summary>
		public string ValueToSet
		{
			get { return this.Arguments[0]; }
		}
		
		/// <summary>
		/// The values to set the specified <see cref="PropertyType">property</see>.
		/// </summary>
		public Collection<string> ValuesToSet
		{
			get 
			{
				if (this.valuesToSet == null)
				{
					this.valuesToSet = new Collection<string>();
					
					for (int i=0; i < this.Arguments.Count - 1; i++)
					{
						this.valuesToSet.Add(this.Arguments[i]);
					}
				}
				
				return this.valuesToSet;
			}
		}
		
		#endregion
		
		#region Public methods
		
		/// <summary>
		/// Executes this command
		/// </summary>
		/// <param name="context">The execution context used to execute this command</param>
		[CLSCompliant(false)]
		public override void Execute(IExecutionContext context)
		{
			switch (this.CommandType)
			{
				case CommandType.SetValue:
					this.ExecuteSetValueCommand(context);
					break;
				case CommandType.SetValues:
					this.ExecuteSetMultipleValueCommand(context);
					break;
				default:
					base.Execute(context);
					break;
			}
		}
		
		#endregion
		
		#region Private methods
		
		/// <summary>
		/// Executes the set value command for a given <see cref="PropertyType">property</see>
		/// </summary>
		/// <param name="context">The execution context used to execute this command</param>
		private void ExecuteSetValueCommand(IExecutionContext context)
		{
			switch (this.PropertyType)
			{
				case PropertyType.Text:
					this.SetText(context);
					break;
				case PropertyType.SelectedItem:
					this.SetSelectedItem(context);
					break;
				case PropertyType.Checked:
					this.SetChecked(context);
					break;
				case PropertyType.Value:
			        throw new NotImplementedException("SetValue for PropertyType.Value.");
				case PropertyType.FileName:
					this.SetFileName(context);
					break;
				default:
					throw new ArgumentOutOfRangeException(string.Format(CultureInfo.InvariantCulture, "Unable to execute set value command using unknown property type: {0}.", this.PropertyType));
			}
		}
		
		/// <summary>
		/// Executes the set multiple value command for a given <see cref="PropertyType">property</see>
		/// </summary>
		/// <param name="context">The execution context used to execute this command</param>
		private void ExecuteSetMultipleValueCommand(IExecutionContext context)
		{
			switch (this.PropertyType)
			{
				case PropertyType.SelectedItem:
					this.SetSelectedItems(context);
					break;
				default:
					throw new ArgumentOutOfRangeException(string.Format(CultureInfo.InvariantCulture, "Unable to validate property using unknown property type: {0}.", this.PropertyType));
			}
		}
		
		/// <summary>
		/// Sets the checked attribute of an <see cref="WatiN.Core.Element">element</see>
		/// </summary>
		/// <param name="context">The execution context used to execute this command</param>
		private void SetChecked(IExecutionContext context)
		{
			WatiN.Core.Element element = this.FindMethod.Execute(context);
			WatiN.Core.RadioCheck radioCheck = new RadioCheck(element.DomContainer, (mshtml.IHTMLInputElement) element.HTMLElement);
			
            bool value;
			if(bool.TryParse(this.ValueToSet, out value))
			{
			    radioCheck.Checked = value;
			}
		}
		
		/// <summary>
		/// Sets the selected item of an <see cref="WatiN.Core.Element">element</see>
		/// </summary>
		/// <param name="context">The execution context used to execute this command</param>
		private void SetSelectedItem(IExecutionContext context)
		{
			WatiN.Core.Element element = this.FindMethod.Execute(context);
			
			WatiN.Core.SelectList selectList = new SelectList(element);
			selectList.SelectByValue(this.ValueToSet);
		}
		
		
		/// <summary>
		/// Sets the selected items of an <see cref="WatiN.Core.Element">element</see>
		/// </summary>
		/// <param name="context">The execution context used to execute this command</param>
		private void SetSelectedItems(IExecutionContext context)
		{
			WatiN.Core.Element element = this.FindMethod.Execute(context);
			
			WatiN.Core.SelectList selectList = new SelectList(element);
			
			foreach(string value in this.ValuesToSet)
			{
				selectList.SelectByValue(value);
			}
			
		}
		
		/// <summary>
		/// Sets the <see cref="TextField.Value">Text field's value</see>
		/// </summary>
		/// <param name="context">The execution context used to execute this command</param>
		private void SetText(IExecutionContext context)
		{
			WatiN.Core.TextField textField = new TextField(this.FindMethod.Execute(context));
			textField.TypeText(this.ValueToSet);
		}
		
		/// <summary>
		/// Sets the <see cref="WatiN.Core.FileUpload.FileName">File name</see> for a file upload element
		/// </summary>
		/// <param name="context">The execution context used to execute this command</param>
		private void SetFileName(IExecutionContext context)
		{
			WatiN.Core.FileUpload fileUpload = new FileUpload(this.FindMethod.Execute(context));
			fileUpload.Set(this.ValueToSet);
		}
		
		#endregion
	}
}
